
package com.chongchong.multifile.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chongchong.core.boot.ctrl.SysController;
import com.chongchong.core.mp.support.Condition;
import com.chongchong.core.mp.support.Query;
import com.chongchong.core.secure.SysUser;
import com.chongchong.core.tool.api.R;
import com.chongchong.multifile.entity.Chunk;
import com.chongchong.multifile.entity.FileList;
import com.chongchong.multifile.service.IChunkService;
import com.chongchong.multifile.utils.CommonConstant;
import com.chongchong.multifile.utils.ExcelUtil;
import com.chongchong.multifile.vo.CheckChunkVO;
import com.chongchong.multifile.vo.ChunkUploadVO;
import com.chongchong.multifile.vo.ChunkVO;
import com.chongchong.multifile.wrapper.ChunkWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.*;

/**
 * 文件分块表 控制器
 *
 * @author en
 * @since 2022-07-18
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/chunk")
@Api(value = "文件分块表", tags = "文件分块表接口")
public class ChunkController extends SysController {

	private IChunkService chunkService;

	private static final String UTF8 = "UTF-8";

	/**
	* 详情
	*/
	@GetMapping("/detail")
    @ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入chunk")
	public R<ChunkVO> detail(Chunk chunk) {
		Chunk detail = chunkService.getOne(Condition.getQueryWrapper(chunk));
		return R.data(ChunkWrapper.build().entityVO(detail));
	}




	/**
	 * 查询用户报告申请记录列表
	 */
//    @ApiOperation("查询用户报告申请记录列表")
//    @PreAuthorize("@ss.hasPermi('background:report:list')")
//    @GetMapping("/list")
//    public TableDataInfo list(BackFileVO backUserReportVO)
//    {
//        startPage();
//        List<BackFileVO> list = backFileService.selectBackFileList(backUserReportVO);
//        return getDataTable(list);
//    }

	/**
	 * 上传文件
	 */
	@ApiOperation("上传文件")
	@PostMapping("/upload")
	public R<ChunkUploadVO> postFileUpload(@ModelAttribute Chunk chunk, HttpServletResponse response)
	{
		int i = chunkService.postFileUpload(chunk, response);
		boolean r = i>0 ? true : false ;
		if(r){
			ChunkUploadVO c = new ChunkUploadVO();
			c.setNeedMerge(true);
			return R.data(c);
		}

		return R.status(r);
	}

	/**
	 * 检查文件上传状态
	 */
	@ApiOperation("检查文件上传状态")
	@GetMapping("/upload")
	public R<CheckChunkVO> getFileUpload(@ModelAttribute Chunk chunk, HttpServletResponse response)
	{
		//查询根据md5查询文件是否存在
		CheckChunkVO fileUpload = chunkService.getFileUpload(chunk, response);
		return R.data(fileUpload);
	}

	/**
	 * 删除用户报告申请记录
	 */
	@ApiOperation("删除文件")
	@DeleteMapping("/delete/{id}")
	public R remove(@PathVariable("id") Long id)
	{
		int count = chunkService.deleteBackFileByIds(id);
		boolean r = count>0 ? true : false ;
		return R.status(r);
	}

	/**
	 * 检查文件上传状态
	 */
	@ApiOperation("合并文件")
	@PostMapping("/merge")
	public R<Long> merge(FileList fileInfo, SysUser user)
	{
		fileInfo.setCreateUserId(user.getUserId());
		int i = chunkService.mergeFile(fileInfo);
		if(i == CommonConstant.UPDATE_EXISTS.intValue()){
			//应对合并时断线导致的无法重新申请合并的问题
			return R.data(null,"已合并,无需再次提交");
		}
		boolean r = i > 0 ? true : false;
		if(i>0){
			return R.data(fileInfo.getId());
		}
		return R.fail("合并失败");
	}

	/**
	 * 查询文件分片管理列表
	 */
	@ApiOperation("查询文件分片管理列表")
	//@PreAuthorize("@ss.hasPermi('background:chunk:list')")
	@GetMapping("/list")
	public R<IPage<Chunk>> list(Chunk chunk, Query query)
	{
		IPage<Chunk> page = chunkService.page(Condition.getPage(query), Condition.getQueryWrapper(chunk));;;
		return R.data(page);
	}

	/**
	 * 导出文件分片管理列表
	 */
	@ApiOperation("导出文件分片管理列表")
	@GetMapping("/export")
	public R export(Chunk chunk)
	{
		List<Chunk> list = chunkService.selectChunkList(chunk);
		ExcelUtil<Chunk> util = new ExcelUtil<Chunk>(Chunk.class);
		boolean r = (Integer)util.exportExcel(list, "chunk").get("code") == 200 ? true:false;
		return R.status(r) ;
	}

	/**
	 * 获取文件分片管理详细信息
	 */
	@ApiOperation("获取文件分片管理详细信息")
	@GetMapping(value = "/{id}")
	public R<Chunk> getInfo(@PathVariable("id") Long id)
	{
		Chunk chunk = chunkService.selectChunkById(id);
		return R.data(chunk);
	}

	/**
	 * 新增文件分片管理
	 */
	@ApiOperation("新增文件分片管理")
	@PostMapping
	public R<Long> add(@RequestBody Chunk chunk)
	{
		chunkService.insertChunk(chunk);
		return R.data(chunk.getId());
	}

	/**
	 * 修改文件分片管理
	 */
	@ApiOperation("修改文件分片管理")
	@PutMapping
	public R edit(@RequestBody Chunk chunk)
	{
		int count = chunkService.updateChunk(chunk);
		boolean r = count>0 ? true : false ;
		return R.status(r);
	}

	/**
	 * 删除文件分片管理
	 */
	@ApiOperation("删除文件分片管理")
	@DeleteMapping("/{ids}")
	public R remove(@PathVariable Long[] ids)
	{
		int count = chunkService.deleteChunkByIds(ids);
		boolean r = count>0 ? true : false ;
		return R.status(r);
	}


	/**
	 * 单线程下载
	 * @param filePath
	 * @param size
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@GetMapping("/download")
	@ApiOperation(value = "文件下载",notes = "文件下载")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "size", value = "文件大小", paramType = "query", dataType = "string"),
		@ApiImplicitParam(name = "filePath", value = "文件路径", paramType = "query", dataType = "string")
	})
	public void download(@RequestParam("filePath") String filePath,@RequestParam("size") long size, HttpServletRequest request, HttpServletResponse response) throws IOException {
		File file = new File(filePath);
		response.setCharacterEncoding(UTF8);
		InputStream is = null;
		OutputStream os = null;
		try {
			// 分片下载 Range表示方式 bytes=100-1000  100-
			long fSize = size;
			response.setContentType("application/x-download");
			String fileName = URLEncoder.encode(file.getName(), UTF8);
			response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
			// 支持分片下载
			response.setHeader("Accept-Range", "bytes");
			response.setHeader("fSize", String.valueOf(fSize));
			response.setHeader("fName", fileName);

			long pos = 0, last = fSize - 1, sum = 0;
			if (null != request.getHeader("Range")) {
				response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
				String numberRange = request.getHeader("Range").replaceAll("bytes=", "");
				String[] strRange = numberRange.split("-");
				if (strRange.length == 2) {
					pos = Long.parseLong(strRange[0].trim());
					last = Long.parseLong(strRange[1].trim());
					if (last > fSize-1) {
						last = fSize - 1;
					}
				} else {
					pos = Long.parseLong(numberRange.replaceAll("-", "").trim());
				}
			}
			long rangeLength = last - pos + 1;
			String contentRange = new StringBuffer("bytes").append(pos).append("-").append(last).append("/").append(fSize).toString();
			response.setHeader("Content-Range", contentRange);
			response.setHeader("Content-Length", String.valueOf(rangeLength));

			os = new BufferedOutputStream(response.getOutputStream());
			is = new BufferedInputStream(new FileInputStream(file));
			is.skip(pos);
			byte[] buffer = new byte[1024];
			int length = 0;
			while (sum < rangeLength) {
				int readLength = (int) (rangeLength - sum);
				length = is.read(buffer, 0, (rangeLength - sum) <= buffer.length ? readLength : buffer.length);
				sum += length;
				os.write(buffer,0, length);
			}
			System.out.println("下载完成");
		}finally {
			if (is != null){
				is.close();
			}
			if (os != null){
				os.close();
			}
		}
	}

	/**
	 * 多线程分片下载
	 * @param filePath
	 * @param size
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	@GetMapping("/downloadByBlock")
	@ApiOperation(value = "文件分片下载",notes = "文件分片下载")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "size", value = "文件大小", paramType = "query", dataType = "string"),
		@ApiImplicitParam(name = "filePath", value = "文件路径", paramType = "query", dataType = "string")
	})
	public void downloadByBlock(@RequestParam("filePath") String filePath,@RequestParam("size") long size, HttpServletRequest request, HttpServletResponse response) throws Exception {
		log.info("多线程分片下载开始。。。。。。。。。。。");
		log.info("文件路径---------"+filePath);
		File file = new File(filePath);
		log.info("文件是否存在-----"+file.exists());
		response.setCharacterEncoding(UTF8);
		final InputStream is = new BufferedInputStream(new FileInputStream(file));
		final OutputStream os = new BufferedOutputStream(response.getOutputStream());
		final long startTime = System.currentTimeMillis();
		try {
			// 分片下载 Range表示方式 bytes=100-1000  100-
			long fSize = size;
			System.out.println("fsize-----"+fSize);
			response.setContentType("application/x-download");
			String fileName = URLEncoder.encode(file.getName(), UTF8);
			response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
			// 支持分片下载
			response.setHeader("Accept-Range", "bytes");
			response.setHeader("fSize", String.valueOf(fSize));
			response.setHeader("fName", fileName);
			response.setHeader("Content-Length", String.valueOf(fSize));
			//分块数
			int blockNum = 5;
			// 每个线程下载的快大小
			long slice = fSize / blockNum;
			//开5个线程
			ExecutorService executor = Executors.newFixedThreadPool(5);
			for (int i = 0; i < blockNum; i++) {
				long start = i * slice;
				long end = (i + 1) * slice - 1;
				if (i == blockNum - 1) {
					start = i * slice;
					end = fSize;
				}
				//字节范围
				response.setHeader("Content-Range", "bytes=" + start + "-" + end + "/" + fSize);
				long finalStart = start;
				long finalEnd = end;
				executor.submit(() -> {
					try {
						//跳过startPos个字节，表明该线程只下载自己负责哪部分文件。
						is.skip(finalStart);
						System.out.println("起始位置" + finalStart);
						int rangeLength = Long.valueOf(finalEnd - finalStart).intValue() + 1;
						byte[] buffer = new byte[1024];
						int length = 0;
						//int sum = 0;
						while ((length=is.read(buffer))!=-1) {
							os.write(buffer,0, length);
						}
						log.info(Thread.currentThread().getName()+"下载完成----"+finalStart+"----"+finalEnd+"------"+rangeLength);
					} catch (Exception e) {
						log.info(Thread.currentThread().getName() + " 下载异常: " + e.getMessage());
						e.printStackTrace();
					}
				}).get(1, TimeUnit.MINUTES);
			}
		}finally {
			if (is != null){
				is.close();
			}
			if (os != null){
				os.close();
			}
		}
		long endTime = System.currentTimeMillis();
		log.info("多线程处理文件下载耗时：" + (endTime - startTime) + "ms");
	}


//	/**
//	 * 断点下载（如果初始全量下载，跟普通下载没什么两样，文件太大可以使用多线程分块下载方法）
//	 * @param request
//	 * @param response
//	 * @param range: 完整下载时传：-
//	 * @param filePath
//	 */
//	@GetMapping("/download")
//	@ApiOperation(value = "文件下载",notes = "文件下载")
//	public void download(HttpServletRequest request, HttpServletResponse response,
//					 @RequestHeader(required = false) String range,@RequestParam String filePath) {
//		// 文件目录
//		File file = new File(filePath);
//		// 开始下载位置
//		long startByte = 0;
//		// 结束下载位置
//		long endByte = file.length() - 1;
//		// 有range的话
//		if (range != null && range.contains("bytes=") && range.contains("-")) {
//			range = range.substring(range.lastIndexOf("=") + 1).trim();
//			String ranges[] = range.split("-");
//			try {
//				// 判断range的类型
//				if (ranges.length == 1) {
//					// 类型一：bytes=-2343
//					if (range.startsWith("-")) {
//						endByte = Long.parseLong(ranges[0]);
//					}
//					// 类型二：bytes=2343-
//					else if (range.endsWith("-")) {
//						startByte = Long.parseLong(ranges[0]);
//					}
//				}
//				// 类型三：bytes=22-2343
//				else if (ranges.length == 2) {
//					startByte = Long.parseLong(ranges[0]);
//					endByte = Long.parseLong(ranges[1]);
//				}
//			} catch (NumberFormatException e) {
//				startByte = 0;
//				endByte = file.length() - 1;
//			}
//		}
//		// 要下载的长度（为啥要加一问小学数学老师去）
//		long contentLength = endByte - startByte + 1;
//		// 文件名
//		String fileName = file.getName();
//		// 文件类型
//		String contentType = request.getServletContext().getMimeType(fileName);
//		// 解析断点续传相关信息
//		response.setHeader("Accept-Ranges", "bytes");
//		// 若客户端传来Range，说明之前下载了一部分，设置206状态(SC_PARTIAL_CONTENT)
//		response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
//		response.setContentType(contentType);
//		response.setHeader("Content-Type", contentType);
//		// 这里文件名换你想要的，inline表示浏览器直接实用（我方便测试用的）
//		// 参考资料：http://hw1287789687.iteye.com/blog/2188500
//		response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
//		response.setHeader("Content-Length", String.valueOf(contentLength));
//		// [要下载的开始位置]-[结束位置]/[文件总大小]
//		response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + file.length());
//		response.addHeader("Access-Contro1-A11ow-0rigin", "*");
//		BufferedOutputStream outputStream = null;
//		RandomAccessFile randomAccessFile = null;
//		// 已传送数据大小
//		long transmitted = 0;
//		try {
//			randomAccessFile = new RandomAccessFile(file, "r");
//			outputStream = new BufferedOutputStream(response.getOutputStream());
//			//byte[] buff = new byte[4096];
//			int len = 0;
//			randomAccessFile.seek(startByte);
//			byte[] buffer = new byte[1024];
//			int lenth = 0;
//			//1 这里循环读 循环写
//			while ((lenth = randomAccessFile.read(buffer)) != -1) {
//				lenth += buffer.length;
//				outputStream.write(buffer);
//				if (lenth == contentLength) {
//					break;
//				}
//			}
//			// contentLength）要放前面！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
//			// 不然会会先读取randomAccessFile，造成后面读取位置出错，找了一天才发现问题所在
////			while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) {
////				outputStream.write(buff, 0, len);
////				transmitted += len;
////				System.out.println("transmitted-----"+transmitted);
////			}
////			// 处理不足buff.length部分
////			if (transmitted < contentLength) {
////				len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted));
////				outputStream.write(buff, 0, len);
////				transmitted += len;
////			}
//			outputStream.flush();
//			response.flushBuffer();
//			//randomAccessFile.close();
//			log.info("下载完毕：" + startByte + "-" + endByte + "：" + transmitted);
//		} catch (ClientAbortException e) {
//			e.printStackTrace();
//			log.info("用户停止下载：" + startByte + "-" + endByte + "：" + transmitted);
//			// 捕获此异常表示拥护停止下载
//		} catch (IOException e) {
//			log.info("下载异常:", e);
//		} finally {
//			try {
//				if (randomAccessFile != null) {
//					randomAccessFile.close();
//				}
//				if (outputStream != null){
//					outputStream.close();
//				}
//			} catch (IOException e) {
//				log.info("下载异常:", e);
//			}
//		}
//	}

//	/**
//	 *
//	 * @param request
//	 * @param response
//	 * @param blockNum 分块数量
//	 * @param size
//	 * @param filePath
//	 */
//	@GetMapping("/downloadByBlock")
//	@ApiOperation(value = "文件分片下载",notes = "文件分片下载")
//	public void download(HttpServletRequest request, HttpServletResponse response,
//						 int blockNum, int size, String filePath) throws InterruptedException {
//		// 要写入的文件
//		final File file = new File(filePath);
//		size = (int)file.length();
//		System.out.println("size---->"+size);
//		// 文件名
//		String fileName = file.getName();
//		// 文件类型
//		String contentType = request.getServletContext().getMimeType(fileName);
//		// 解析断点续传相关信息
//		response.setHeader("Accept-Ranges", "bytes");
//		// 若客户端传来Range，说明之前下载了一部分，设置206状态(SC_PARTIAL_CONTENT)
//		response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
//		response.setContentType(contentType);
//		response.setHeader("Content-Type", contentType);
//		// 这里文件名换你想要的，inline表示浏览器直接实用（我方便测试用的）
//		// 参考资料：http://hw1287789687.iteye.com/blog/2188500
//		response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
//		response.setHeader("Content-Length", String.valueOf(size));
//		// [要下载的开始位置]-[结束位置]/[文件总大小]
//		response.setHeader("Content-Range", "bytes " + 0 + "-" + (size-1) + "/" + file.length());
//		Vector<Thread> threads = new Vector<>();
//		final int block = (size + blockNum - 1) / blockNum;// 每个线程下载的快大小
//		for (int i = 0; i < blockNum; i++) {
//			final int a = i;
//			Thread childrenThread = new Thread(new Runnable() {
//				int start = block * a;// 开始位置
//				int end = block * (a + 1) - 1;// 结束位置
//				long contentLength = end - start + 1;
//				@Override
//				public void run() {
//					RandomAccessFile randomAccessFile = null;
//					BufferedOutputStream outputStream = null;
//					// 已传送数据大小
//					long transmitted = 0;
//
//					try {
//						outputStream = new BufferedOutputStream(response.getOutputStream());
//						randomAccessFile = new RandomAccessFile(file, "rwd");// 建立随机访问
//						byte[] buff = new byte[4096];
//						int len = 0;
//						randomAccessFile.seek(start);
//						// contentLength）要放前面！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
//						// 不然会会先读取randomAccessFile，造成后面读取位置出错，找了一天才发现问题所在
//						while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) {
//							outputStream.write(buff, 0, len);
//							transmitted += len;
//						}
//						// 处理不足buff.length部分
//						if (transmitted < contentLength) {
//							len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted));
//							outputStream.write(buff, 0, len);
//							transmitted += len;
//						}
//
//						outputStream.flush();
//						response.flushBuffer();
//						//randomAccessFile.close();
//						log.info("线程:" + a + "下载完成：" + start + "-" + end + "：" + transmitted);
//					} catch (IOException e1) {
//						e1.printStackTrace();
//					} finally {
//						try {
//							if (randomAccessFile != null) {
//								randomAccessFile.close();
//							}
////							if (outputStream != null){
////								outputStream.close();
////							}
//						} catch (IOException e) {
//							e.printStackTrace();
//						}
//					}
//				}
//			});
//			threads.add(childrenThread);
//			childrenThread.start();
//		}
//		//主线程
//		for(Thread thread : threads){
//			thread.join(); //使用join来保证childrenThread的5个线程都执行完后，才执行主线程
//		}
//		//Thread.sleep(5000);
//		System.out.println("结束。。。。。。。");
//	}



//	@GetMapping("/downloadByBlock")
//	@ApiOperation(value = "文件分片下载",notes = "文件分片下载")
//	@ApiImplicitParams({
//		@ApiImplicitParam(name = "size", value = "文件大小", paramType = "query", dataType = "string"),
//		@ApiImplicitParam(name = "filePath", value = "文件路径", paramType = "query", dataType = "string")
//	})
//	public void downloadByBlock(HttpServletRequest request, HttpServletResponse response,
//								long size, String filePath) throws Exception {
//		// 要写入的文件
//		final File file = new File(filePath);
//		log.info("文件size---->"+size);
//		// 文件名
//		String fileName = file.getName();
//		// 文件类型
//		String contentType = request.getServletContext().getMimeType(fileName);
//		// 解析断点续传相关信息
//		response.setHeader("Accept-Ranges", "bytes");
//		// 若客户端传来Range，说明之前下载了一部分，设置206状态(SC_PARTIAL_CONTENT)
//		response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
//		//response.setContentType(contentType);
//		response.setHeader("Content-Type", "application/x-download");
//		// 这里文件名换你想要的，inline表示浏览器直接实用（我方便测试用的）
//		// 参考资料：http://hw1287789687.iteye.com/blog/2188500
//		response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
//		response.setHeader("Content-Length", String.valueOf(size));
//		// [要下载的开始位置]-[结束位置]/[文件总大小]
//		//response.setHeader("Content-Range", "bytes " + 0 + "-" + (size-1) + "/" + size);
//		final OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());;
//		final RandomAccessFile rf = new RandomAccessFile(file, "rw");;
//		//分块数
//		int blockNum = 5;
//		// 每个线程下载的快大小
//		long slice = size / blockNum;
//
//		//开5个线程
//		ExecutorService executor = Executors.newFixedThreadPool(5);
//		final long startTime = System.currentTimeMillis();
//		for (int i = 0; i < blockNum; i++) {
//			long start = i * slice;
//			long end = (i + 1) * slice - 1;
//			if (i == blockNum - 1) {
//				start = i * slice;
//				end = size;
//			}
//			//字节范围
//			response.setHeader("Content-Range", "bytes=" + start + "-" + end);
//			long finalStart = start;
//			long finalEnd = end;
//			executor.submit(() -> {
//				try {
//					//跳过startPos个字节，表明该线程只下载自己负责哪部分文件。
//					rf.seek(finalStart);
//					System.out.println("起始位置" + finalStart);
//					int lent = Long.valueOf(finalEnd - finalStart).intValue() + 1;
//					byte[] buffer = new byte[1024];
//					int lenth = 0;
//					//1 这里循环读 循环写
//					while ((lenth = rf.read(buffer)) != -1) {
//						//lenth += buffer.length;
//						outputStream.write(buffer,0,lenth);
////						if (lenth == lent) {
////							break;
////						}
//					}
//					outputStream.flush();
//					response.flushBuffer();
//					log.info(Thread.currentThread().getName()+"下载完成----"+finalStart+"----"+finalEnd+"------"+lent);
//				} catch (Exception e) {
//					log.info(Thread.currentThread().getName() + " 下载异常: " + e.getMessage());
//					e.printStackTrace();
//				}
//			}).get(1, TimeUnit.MINUTES);
//		}
//		response.flushBuffer();
//		if(outputStream!=null){
//			outputStream.close();
//		}
//		rf.close();
//		long endTime = System.currentTimeMillis();
//		log.info("多线程处理文件下载耗时：" + (endTime - startTime) + "ms");
//	}








}
